#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "NamedElement.h"
#include "Namespace.h"
#include "RedefinableElement.h"
#include "Vertex.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Behavior;
class Classifier;
class ConnectionPointReference;
class Constraint;
class Pseudostate;
class RedefinableElement;
class Region;
class StateMachine;
class Trigger;

/// <summary>
/// State
/// A State models a situation during which some (usually implicit) invariant
/// condition holds.
/// </summary>
class UMLMODEL_EXPORT State : public NamedElement, public Namespace, public RedefinableElement, public Vertex {

public: // Constructors and destructors
    explicit State(const QString& umlType="uml::State");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// containingStateMachine
    /// The query containingStateMachine() returns the StateMachine that contains the
    /// State either directly or transitively.
    /// </summary>
    shared_ptr<StateMachine> containingStateMachine() const override;

    /// <summary>
    /// isConsistentWith
    /// The query isConsistentWith() specifies that a redefining State is consistent
    /// with a redefined State provided that the redefining State is an extension of the
    /// redefined State A simple State can be redefined (extended) to become a composite
    /// State (by adding one or more Regions) and a composite State can be redefined
    /// (extended) by adding Regions and by adding Vertices, States, and Transitions to
    /// inherited Regions. All States may add or replace entry, exit, and 'doActivity'
    /// Behaviors.
    /// </summary>
    bool isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const override;

    /// <summary>
    /// isRedefinitionContextValid
    /// The query isRedefinitionContextValid() specifies whether the redefinition
    /// contexts of a State are properly related to the redefinition contexts of the
    /// specified State to allow this element to redefine the other. This means that the
    /// containing Region of a redefining State must redefine the containing Region of
    /// the redefined State.
    /// </summary>
    bool isRedefinitionContextValid(shared_ptr<RedefinableElement> redefinedElement) const override;

public: // Properties
    /// <summary>
    /// connections getter
    /// The entry and exit connection points used in conjunction with this (submachine)
    /// State, i.e., as targets and sources, respectively, in the Region with the
    /// submachine State. A connection point reference references the corresponding
    /// definition of a connection point Pseudostate in the StateMachine referenced by
    /// the submachine State.
    /// </summary>
    vector<shared_ptr<ConnectionPointReference>>& connections();

    /// <summary>
    /// connectionPoints getter
    /// The entry and exit Pseudostates of a composite State. These can only be entry or
    /// exit Pseudostates, and they must have different names. They can only be defined
    /// for composite States.
    /// </summary>
    vector<shared_ptr<Pseudostate>>& connectionPoints();

    /// <summary>
    /// deferrableTriggers getter
    /// A list of Triggers that are candidates to be retained by the StateMachine if
    /// they trigger no Transitions out of the State (not consumed). A deferred Trigger
    /// is retained until the StateMachine reaches a State configuration where it is no
    /// longer deferred.
    /// </summary>
    vector<shared_ptr<Trigger>>& deferrableTriggers();

    /// <summary>
    /// doActivity getter
    /// An optional Behavior that is executed while being in the State. The execution
    /// starts when this State is entered, and ceases either by itself when done, or
    /// when the State is exited, whichever comes first.
    /// </summary>
    shared_ptr<Behavior> doActivity() const;

    /// <summary>
    /// doActivity setter
    /// An optional Behavior that is executed while being in the State. The execution
    /// starts when this State is entered, and ceases either by itself when done, or
    /// when the State is exited, whichever comes first.
    /// </summary>
    void setDoActivity(shared_ptr<Behavior> value);

    /// <summary>
    /// entry getter
    /// An optional Behavior that is executed whenever this State is entered regardless
    /// of the Transition taken to reach the State. If defined, entry Behaviors are
    /// always executed to completion prior to any internal Behavior or Transitions
    /// performed within the State.
    /// </summary>
    shared_ptr<Behavior> entry() const;

    /// <summary>
    /// entry setter
    /// An optional Behavior that is executed whenever this State is entered regardless
    /// of the Transition taken to reach the State. If defined, entry Behaviors are
    /// always executed to completion prior to any internal Behavior or Transitions
    /// performed within the State.
    /// </summary>
    void setEntry(shared_ptr<Behavior> value);

    /// <summary>
    /// exit getter
    /// An optional Behavior that is executed whenever this State is exited regardless
    /// of which Transition was taken out of the State. If defined, exit Behaviors are
    /// always executed to completion only after all internal and transition Behaviors
    /// have completed execution.
    /// </summary>
    shared_ptr<Behavior> exit() const;

    /// <summary>
    /// exit setter
    /// An optional Behavior that is executed whenever this State is exited regardless
    /// of which Transition was taken out of the State. If defined, exit Behaviors are
    /// always executed to completion only after all internal and transition Behaviors
    /// have completed execution.
    /// </summary>
    void setExit(shared_ptr<Behavior> value);

    /// <summary>
    /// isComposite getter
    /// A state with isComposite=true is said to be a composite State. A composite State
    /// is a State that contains at least one Region.
    /// </summary>
    bool isComposite() const;

    /// <summary>
    /// isComposite setter
    /// A state with isComposite=true is said to be a composite State. A composite State
    /// is a State that contains at least one Region.
    /// </summary>
    void setIsComposite(bool value);

    /// <summary>
    /// isOrthogonal getter
    /// A State with isOrthogonal=true is said to be an orthogonal composite State An
    /// orthogonal composite State contains two or more Regions.
    /// </summary>
    bool isOrthogonal() const;

    /// <summary>
    /// isOrthogonal setter
    /// A State with isOrthogonal=true is said to be an orthogonal composite State An
    /// orthogonal composite State contains two or more Regions.
    /// </summary>
    void setIsOrthogonal(bool value);

    /// <summary>
    /// isSimple getter
    /// A State with isSimple=true is said to be a simple State A simple State does not
    /// have any Regions and it does not refer to any submachine StateMachine.
    /// </summary>
    bool isSimple() const;

    /// <summary>
    /// isSimple setter
    /// A State with isSimple=true is said to be a simple State A simple State does not
    /// have any Regions and it does not refer to any submachine StateMachine.
    /// </summary>
    void setIsSimple(bool value);

    /// <summary>
    /// isSubmachineState getter
    /// A State with isSubmachineState=true is said to be a submachine State Such a
    /// State refers to another StateMachine(submachine).
    /// </summary>
    bool isSubmachineState() const;

    /// <summary>
    /// isSubmachineState setter
    /// A State with isSubmachineState=true is said to be a submachine State Such a
    /// State refers to another StateMachine(submachine).
    /// </summary>
    void setIsSubmachineState(bool value);

    /// <summary>
    /// redefinedState getter
    /// The State of which this State is a redefinition.
    /// </summary>
    shared_ptr<State> redefinedState() const;

    /// <summary>
    /// redefinedState setter
    /// The State of which this State is a redefinition.
    /// </summary>
    void setRedefinedState(shared_ptr<State> value);

    /// <summary>
    /// redefinitionContext getter
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    shared_ptr<Classifier> redefinitionContext() const;

    /// <summary>
    /// redefinitionContext setter
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    void setRedefinitionContext(shared_ptr<Classifier> value);

    /// <summary>
    /// regions getter
    /// The Regions owned directly by the State.
    /// </summary>
    vector<shared_ptr<Region>>& regions();

    /// <summary>
    /// stateInvariant getter
    /// Specifies conditions that are always true when this State is the current State.
    /// In ProtocolStateMachines state invariants are additional conditions to the
    /// preconditions of the outgoing Transitions, and to the postcondition of the
    /// incoming Transitions.
    /// </summary>
    shared_ptr<Constraint> stateInvariant() const;

    /// <summary>
    /// stateInvariant setter
    /// Specifies conditions that are always true when this State is the current State.
    /// In ProtocolStateMachines state invariants are additional conditions to the
    /// preconditions of the outgoing Transitions, and to the postcondition of the
    /// incoming Transitions.
    /// </summary>
    void setStateInvariant(shared_ptr<Constraint> value);

    /// <summary>
    /// submachine getter
    /// The StateMachine that is to be inserted in place of the (submachine) State.
    /// </summary>
    shared_ptr<StateMachine> submachine() const;

    /// <summary>
    /// submachine setter
    /// The StateMachine that is to be inserted in place of the (submachine) State.
    /// </summary>
    void setSubmachine(shared_ptr<StateMachine> value);

private: // Fields
    /// <summary>
    /// connections
    /// The entry and exit connection points used in conjunction with this (submachine)
    /// State, i.e., as targets and sources, respectively, in the Region with the
    /// submachine State. A connection point reference references the corresponding
    /// definition of a connection point Pseudostate in the StateMachine referenced by
    /// the submachine State.
    /// </summary>
    vector<shared_ptr<ConnectionPointReference>> connections_;

    /// <summary>
    /// connectionPoints
    /// The entry and exit Pseudostates of a composite State. These can only be entry or
    /// exit Pseudostates, and they must have different names. They can only be defined
    /// for composite States.
    /// </summary>
    vector<shared_ptr<Pseudostate>> connectionPoints_;

    /// <summary>
    /// deferrableTriggers
    /// A list of Triggers that are candidates to be retained by the StateMachine if
    /// they trigger no Transitions out of the State (not consumed). A deferred Trigger
    /// is retained until the StateMachine reaches a State configuration where it is no
    /// longer deferred.
    /// </summary>
    vector<shared_ptr<Trigger>> deferrableTriggers_;

    /// <summary>
    /// doActivity
    /// An optional Behavior that is executed while being in the State. The execution
    /// starts when this State is entered, and ceases either by itself when done, or
    /// when the State is exited, whichever comes first.
    /// </summary>
    shared_ptr<Behavior> doActivity_;

    /// <summary>
    /// entry
    /// An optional Behavior that is executed whenever this State is entered regardless
    /// of the Transition taken to reach the State. If defined, entry Behaviors are
    /// always executed to completion prior to any internal Behavior or Transitions
    /// performed within the State.
    /// </summary>
    shared_ptr<Behavior> entry_;

    /// <summary>
    /// exit
    /// An optional Behavior that is executed whenever this State is exited regardless
    /// of which Transition was taken out of the State. If defined, exit Behaviors are
    /// always executed to completion only after all internal and transition Behaviors
    /// have completed execution.
    /// </summary>
    shared_ptr<Behavior> exit_;

    /// <summary>
    /// isComposite
    /// A state with isComposite=true is said to be a composite State. A composite State
    /// is a State that contains at least one Region.
    /// </summary>
    const static bool isComposite_default_;
    bool isComposite_= isComposite_default_;

    /// <summary>
    /// isOrthogonal
    /// A State with isOrthogonal=true is said to be an orthogonal composite State An
    /// orthogonal composite State contains two or more Regions.
    /// </summary>
    const static bool isOrthogonal_default_;
    bool isOrthogonal_= isOrthogonal_default_;

    /// <summary>
    /// isSimple
    /// A State with isSimple=true is said to be a simple State A simple State does not
    /// have any Regions and it does not refer to any submachine StateMachine.
    /// </summary>
    const static bool isSimple_default_;
    bool isSimple_= isSimple_default_;

    /// <summary>
    /// isSubmachineState
    /// A State with isSubmachineState=true is said to be a submachine State Such a
    /// State refers to another StateMachine(submachine).
    /// </summary>
    const static bool isSubmachineState_default_;
    bool isSubmachineState_= isSubmachineState_default_;

    /// <summary>
    /// redefinedState
    /// The State of which this State is a redefinition.
    /// </summary>
    shared_ptr<State> redefinedState_;

    /// <summary>
    /// redefinitionContext
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    shared_ptr<Classifier> redefinitionContext_;

    /// <summary>
    /// regions
    /// The Regions owned directly by the State.
    /// </summary>
    vector<shared_ptr<Region>> regions_;

    /// <summary>
    /// stateInvariant
    /// Specifies conditions that are always true when this State is the current State.
    /// In ProtocolStateMachines state invariants are additional conditions to the
    /// preconditions of the outgoing Transitions, and to the postcondition of the
    /// incoming Transitions.
    /// </summary>
    shared_ptr<Constraint> stateInvariant_;

    /// <summary>
    /// submachine
    /// The StateMachine that is to be inserted in place of the (submachine) State.
    /// </summary>
    shared_ptr<StateMachine> submachine_;

};

} // namespace uml
